//@author A0100704B
//This class creates the user interface of the program
package crossoff.ui;

import java.awt.*;

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.StyleSheet;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.geom.RoundRectangle2D;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.awt.Color;

import org.jnativehook.GlobalScreen;
import org.jnativehook.NativeHookException;
import org.jnativehook.keyboard.NativeKeyEvent;
import org.jnativehook.keyboard.NativeKeyListener;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.LocalTime;

import crossoff.db.Storage;
import crossoff.logic.CommandAddTask;
import crossoff.logic.CommandLogic;
import crossoff.model.GUIobject;
import crossoff.model.LFobject;
import crossoff.model.Task;

@SuppressWarnings("unused")
public class CrossOffGUI implements DocumentListener, TableModelListener,
ActionListener, NativeKeyListener, WindowListener {
	
	private static final String CROSSOFF_LABEL = "CROSSOFF";
	
	//Font sizes for different labels
	private static final int FONT_SIZE_DATELABEL = 60;
	private static final int FONT_SIZE_LABEL = 20;
	private static final int FONT_SIZE_MODELABEL = 35;
	private static final int FONT_SIZE_HELP_PAGE = 16;
	private static final int FONT_SIZE_READ_PAGE = 16;
	private static final int FONT_SIZE_TABLE = 14;
	private static final int FONT_SIZE_COMMAND = 20;
	
	private static final int[] DARK_GREEN = {0, 128, 128};
	private static final int[] GREEN = {32, 178, 170};
	private static final int[] LIGHT_GREEN = {224, 255, 255};
	
	//Bounds for different components
	private static final int[] BOUNDS_MODE_LABEL = {16, 30, 373, 46};
	private static final int[] BOUNDS_DATE_LABEL = {203, 15, 241, 76};
	private static final int[] BOUNDS_FEEDBACK_LABEL = {6, 291, 438, 32};
	private static final int[] BOUNDS_FRAME = {100, 100, 453, 376};
	private static final int[] BOUNDS_SCROLLPANE = {6, 73, 438, 218};
	private static final int[] BOUNDS_COMMANDBOX = {6, 314, 441, 53};
	
	//Font files
	private static final String BOLD_FONT_FILE = "fonts/Adventure Subtitles.ttf";
	private static final String NORMAL_FONT_FILE = "fonts/eurostile.ttf";
	private static final String HELP_PAGE_FILE = "helpPage.txt";
	
	//Input text
	private static final String INPUT_HELP = "help";
	private static final String INPUT_READ = "read";
	
	//Modes of CrossOff
	private static final String MODE_EDIT = "EDIT";
	private static final String MODE_DEFAULT = "TO-DO";
	private static final String MODE_HELP = "HELP";
	private static final String MODE_READ = "READ";
	
	private static final String FONT_STYLE_HEADING2 = "h2{color: #40E0D0}";
	private static final String FONT_STYLE_BOLD = "b{color:yellow}";
	private static final String HELP_PAGE_CONTENT_TYPE = "text/html";
	
	private static final String EMPTY_STRING = "";
	private static final int TABLE_NUM_COLUMNS = 5;
	private static final int COMMANDBOX_NUM_COLUMNS = 10;
	
    private static final String MESSAGE_ERROR_INITIALIZE = "There was an error initializing task.json. Please check that you have downloaded the latest version.";
    private static final String MESSAGE_ERROR_NATIVE_HOOK = "There was a problem registering the global hotkey.\n"
                    + "For Mavericks OSX Users:\n"
                    + "Please go to Preferences > Security & Privacy > Privacy> Acessibility and check the Jar Launcher checkbox.";
	
	private JFrame frame;
	private JTable table;
	public static JTextField commandInput;
	public static JLabel feedbackLabel, modeLabel;
	private String[] columnNames = { "No.", "Task Description", "Start Date",
			"End Date", "TaskID" };
	private JScrollPane scrollPane;
	private static ArrayList<Task> displayTable;
	private static Point mouseCoordinates;
	private static File boldFontFile, normalFontFile;
	private static Font normalFont, boldFont;
	private static GUIobject displayGUI;

	/**
	 * Launch the application.
	 * @throws IOException
	 */
	public void run() throws IOException {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					frame.setVisible(true);
					commandInput.requestFocusInWindow();
				} catch (Exception e) {
					JOptionPane.showMessageDialog(null, MESSAGE_ERROR_INITIALIZE);
					e.printStackTrace();
					System.exit(0);
				}
			}
		});
	}

	/**
	 * Create the application.
	 * @throws IOException
	 * @throws FontFormatException
	 */
	public CrossOffGUI() throws FontFormatException, IOException {
		initialize();
	}

	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize() throws IOException {
		initialiseFont();

		DateTime currDate = new DateTime();

		scrollPane = new JScrollPane();
		displayGUI = new GUIobject();

		initialiseFrame();
		createFeedbackLabel();
		refreshTable();
		createModeLabel();
		createCommandBox();
		createDateLabel(currDate);
	}

	private void initialiseFont() throws IOException {
		try {
			normalFont = Font.createFont(Font.TRUETYPE_FONT, getClass().getResourceAsStream(NORMAL_FONT_FILE));
			boldFont = Font.createFont(Font.TRUETYPE_FONT, getClass().getResourceAsStream(BOLD_FONT_FILE));
		} catch (FontFormatException e) {
			System.err.println(e.getMessage());
		}
	}

	private void initialiseFrame() {
		frame = new JFrame();
		frame.getContentPane().setBackground(new Color(GREEN[0], GREEN[1], GREEN[2]));
		frame.setBounds(BOUNDS_FRAME[0], BOUNDS_FRAME[1], BOUNDS_FRAME[2], BOUNDS_FRAME[3]);
		frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
		frame.setUndecorated(true);
		frame.getContentPane().setLayout(null);
		setMovable();
		scrollPane.setBounds(BOUNDS_SCROLLPANE[0], BOUNDS_SCROLLPANE[1], BOUNDS_SCROLLPANE[2], BOUNDS_SCROLLPANE[3]);
		frame.getContentPane().add(scrollPane);
		frame.addWindowListener(this);
		frame.setAlwaysOnTop(true);
	}
	
	//Allows the user to move the window around with the mouse
	private void setMovable() {
		mouseCoordinates = null;

		frame.addMouseListener(new MouseListener() {
			public void mouseReleased(MouseEvent e) {
				mouseCoordinates = null;
			}

			public void mousePressed(MouseEvent e) {
				mouseCoordinates = e.getPoint();
			}

			public void mouseExited(MouseEvent e) {
				//Unimplemented method
			}

			public void mouseEntered(MouseEvent e) {
				//Unimplemented method
			}

			public void mouseClicked(MouseEvent e) {
				//Unimplemented method
			}
		});

		frame.addMouseMotionListener(new MouseMotionListener() {
			public void mouseMoved(MouseEvent e) {
				//Unimplemented method
			}

			public void mouseDragged(MouseEvent e) {
				Point currCoords = e.getLocationOnScreen();
				frame.setLocation(currCoords.x - mouseCoordinates.x,
						currCoords.y - mouseCoordinates.y);
			}
		});

	}

	private void createModeLabel() {
		modeLabel = new JLabel(displayGUI.getMode());
		modeLabelSettings();
		frame.getContentPane().add(modeLabel);
	}

	private void modeLabelSettings() {
		Font labelFont = boldFont;
		labelFont = labelFont.deriveFont(Font.PLAIN, FONT_SIZE_MODELABEL);
		
		modeLabel.setFont(labelFont);
		modeLabel.setForeground(Color.WHITE);
		modeLabel.setBounds(BOUNDS_MODE_LABEL[0], BOUNDS_MODE_LABEL[1], BOUNDS_MODE_LABEL[2], BOUNDS_MODE_LABEL[3]);
	}

	private void createFeedbackLabel() {
		feedbackLabelSettings();
		frame.getContentPane().add(feedbackLabel);
	}

	private void feedbackLabelSettings() {
		Font labelFont = boldFont;
		labelFont = labelFont.deriveFont(Font.PLAIN, FONT_SIZE_LABEL);
		
		feedbackLabel = new JLabel(CROSSOFF_LABEL);
		feedbackLabel.setHorizontalAlignment(SwingConstants.RIGHT);
		feedbackLabel.setBounds(BOUNDS_FEEDBACK_LABEL[0], BOUNDS_FEEDBACK_LABEL[1], BOUNDS_FEEDBACK_LABEL[2], BOUNDS_FEEDBACK_LABEL[3]);
		feedbackLabel.setFont(labelFont);
		feedbackLabel.setForeground(Color.WHITE);
	}

	private void createDateLabel(DateTime currDate) {
		int date, month;
		String dayLabel;
		String[] monthNames = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
				"JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };

		date = currDate.getDayOfMonth();
		month = currDate.getMonthOfYear();
		dayLabel = date + " " + monthNames[month - 1];

		JLabel dateLabel = new JLabel(dayLabel);
		dateLabelSettings(dateLabel);
		frame.getContentPane().add(dateLabel);
	}

	private void dateLabelSettings(JLabel dateLabel) {
		Font labelFont = boldFont;
		labelFont = labelFont.deriveFont(Font.PLAIN, FONT_SIZE_DATELABEL);
		
		dateLabel.setHorizontalAlignment(SwingConstants.RIGHT);
		dateLabel.setForeground(Color.WHITE);
		dateLabel.setFont(labelFont);
		dateLabel.setBounds(BOUNDS_DATE_LABEL[0], BOUNDS_DATE_LABEL[1], BOUNDS_DATE_LABEL[2], BOUNDS_DATE_LABEL[3]);
	}

	private void createCommandBox() {
		commandInput = new JTextField();

		commandInputSettings();

		addInputActionListener();
		addInputKeyListener();
		addInputDocumentListener();
	}

	private void commandInputSettings() {
		Font commandFont = normalFont;
		commandFont = commandFont.deriveFont(Font.PLAIN, FONT_SIZE_COMMAND);
		
		commandInput.setForeground(Color.WHITE);
		commandInput.setFont(commandFont);
		commandInput.setBackground(new Color(DARK_GREEN[0], DARK_GREEN[1], DARK_GREEN[2]));
		commandInput.setBounds(BOUNDS_COMMANDBOX[0], BOUNDS_COMMANDBOX[1], BOUNDS_COMMANDBOX[2], BOUNDS_COMMANDBOX[3]);
		frame.getContentPane().add(commandInput);
		commandInput.setColumns(COMMANDBOX_NUM_COLUMNS);
	}

	private void addInputDocumentListener() {
		commandInput.getDocument().addDocumentListener(new DocumentListener() {
			@Override
			public void changedUpdate(DocumentEvent e) {
				checkLive();
			}

			@Override
			public void insertUpdate(DocumentEvent e) {
				checkLive();
			}

			@Override
			public void removeUpdate(DocumentEvent e) {
				checkLive();
			}

			public void checkLive(){
				try {
					if((isReadMode() || isHelpMode()) && commandTyped()){
						displayGUI = new GUIobject();
						refreshMode();
						refreshTable();
						return;
					}
					
					if(commandTyped() && isDefaultMode()){
						displayGUI = CommandLogic.runCommand(commandInput.getText().trim(), false);
					} else if(isDefaultMode()){
						displayGUI = new GUIobject();
					}
					
					refreshMode();
					refreshTable();
					changeFeedback(displayGUI.getFeedback());
					scrollToTask();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
		});
	}
	
	private void addInputKeyListener() {
		commandInput.addKeyListener(new KeyListener(){
			@Override
			public void keyTyped(KeyEvent e) {
				checkFloating(e);
				checkExit(e);
			}

			@Override
			public void keyPressed(KeyEvent e) {
				checkFloating(e);
				checkExit(e);
			}

			@Override
			public void keyReleased(KeyEvent e) {
				checkFloating(e);
				checkExit(e);
			}

			public void checkFloating(KeyEvent e){
				//If input with Ctrl+Enter
				if((!isEditMode() && e.getModifiers() == KeyEvent.CTRL_MASK) 
						&& (e.getKeyCode() == KeyEvent.VK_ENTER)){
					try {
						if(commandTyped()){
							displayGUI = CommandAddTask.addFloating(commandInput.getText().trim());
							String feedback = displayGUI.getFeedback();
							int newTask = displayGUI.getNewTask();

							changeCommandText();
							refreshTable();
							checkNewTaskIndex(newTask);

							if(displayGUI.getToHighlight() != 0){
								scrollToTask();
							}
							changeFeedback(feedback);
						}
					} catch (Exception e1) {
						e1.printStackTrace();
					}
				}
			}

			public void checkExit(KeyEvent e){
				if (e.getKeyCode() == KeyEvent.VK_F4 
						&& e.getModifiers() == KeyEvent.ALT_MASK){ //If key pressed = Alt + F4, exit
					System.exit(0);
				}
			}
		});
	}
	
	//Listener for Enter key
	private void addInputActionListener() {
		commandInput.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				String command = commandInput.getText().trim();
				int newTask = 0;

				try {
					if (!command.isEmpty()) {
						String[] commandSplit = command.split("\\s+");
						if(commandSplit[0].toLowerCase().equals(INPUT_READ) && isValidReadCommand(command)){
							commandInput.setText(EMPTY_STRING); //clear command box after enter
							refreshReading(Integer.parseInt(commandSplit[1])); //read the task
							refreshMode();
							return;
						} else if(command.toLowerCase().equals(INPUT_HELP)){
							commandInput.setText(EMPTY_STRING);
							viewHelpPage();
							return;
						} else if (displayGUI.getMode().equals(MODE_EDIT)) {
							if(command.toLowerCase().equals("reset")){
								displayGUI = new GUIobject();
							}
							else{
								displayGUI = CommandLogic.runEditCommand(command);
							}
						} else {
							displayGUI = CommandLogic.runCommand(command, true);
							newTask = displayGUI.getNewTask();
						}
						setHighlight(newTask);
					}

				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}

			private void setHighlight(int newTask) {
				String feedback = displayGUI.getFeedback();
				changeCommandText();
				refreshMode();
				refreshTable();

				checkNewTaskIndex(newTask);

				if(displayGUI.getToHighlight() != 0){
					scrollToTask();
				}

				changeFeedback(feedback);
			}
		});
	}
	
	//finds the new task if there is one
	private void checkNewTaskIndex(int newTask) {
		if(newTask != 0){
			for(int j = 0; j < displayTable.size(); j++){
				if(displayTable.get(j).getTaskID() == newTask){
					displayGUI.setToHighlight(j+1);
					break;
				}
			}
		}
	}
	
	//scroll to the highlighted task
	private void scrollToTask() {
		int scrollTo = displayGUI.getToHighlight()-1;
		table.getSelectionModel().setSelectionInterval(scrollTo, scrollTo);
		table.scrollRectToVisible(new Rectangle(table.getCellRect(scrollTo, 0, true)));
	}

	private void refreshTable() {
		Font tableFont = normalFont;
		displayTable = displayGUI.getDisplayCache();
		Collections.sort(displayTable);

		int numTasks = displayGUI.getDisplayCache().size();
		int i = 0;
		Object[][] data;
		DateTime start = null, end = null;

		//If LiveFeed exists, add row 0
		if (liveFeedExists()) {
			data = new Object[numTasks+1][TABLE_NUM_COLUMNS];
			LFobject lf = displayGUI.getLiveFeed();
			i = 1;

			if(startDateTimeExists(lf)){
				start = formatStartDate(lf);
			}

			if(endDateTimeExists(lf)){
				end = formatEndDate(lf);
			}

			data[0][0] = 0;
			data[0][1] = lf.getDescription();
			data[0][2] = convertDate(start);
			data[0][3] = convertDate(end);
		} else{
			i = 0;
			data = new Object[numTasks][TABLE_NUM_COLUMNS];
		}

		if (numTasks > 0) {
			for (Task task : displayTable) {
				if(liveFeedExists()){
					data[i][0] = i;
				} else{
					data[i][0] = i+1;
				}

				data[i][1] = task.getDescription();
				data[i][2] = convertDate(task.getStart());
				data[i][3] = convertDate(task.getEnd());
				data[i][4] = task.getTaskID();
				i++;
			}
		}

		createTable(data);
		createTableHeader();
		tableSettings(tableFont);
		
		scrollPane.setViewportView(table);
	}

	private void tableSettings(Font tableFont) {
		table.setFillsViewportHeight(true);
		table.setColumnSelectionAllowed(true);
		table.setCellSelectionEnabled(true);
		table.setRowSelectionAllowed(true);
		
		tableFont = tableFont.deriveFont(Font.PLAIN, FONT_SIZE_TABLE);
		table.setFont(tableFont);
		
		table.setForeground(Color.WHITE);
		table.setBackground(new Color(DARK_GREEN[0], DARK_GREEN[1], DARK_GREEN[2]));
		
		table.setRowHeight(40);
		table.getColumnModel().getColumn(0).setMinWidth(30);
		table.getColumnModel().getColumn(0).setMaxWidth(30);
		table.getColumnModel().getColumn(0).setPreferredWidth(30);
		table.getColumnModel().getColumn(1).setPreferredWidth(200);
		table.getColumnModel().getColumn(2).setPreferredWidth(40);
		table.getColumnModel().getColumn(3).setPreferredWidth(40);
		table.getColumnModel().getColumn(4).setMinWidth(0);
		table.getColumnModel().getColumn(4).setMaxWidth(0);
		table.getColumnModel().getColumn(4).setPreferredWidth(0);
	}

	@SuppressWarnings("serial")
	private void createTableHeader() {
		final JTableHeader tableHeader = table.getTableHeader();
		tableHeader.setDefaultRenderer(new DefaultTableCellRenderer() {
			@Override
			public Component getTableCellRendererComponent(JTable table,
					Object value, boolean isSelected, boolean hasFocus,
					int row, int column) {
				DefaultTableCellRenderer rendererComponent = (DefaultTableCellRenderer) super
						.getTableCellRendererComponent(table, value,
								isSelected, hasFocus, row, column);
				rendererComponent.setBackground(new Color(LIGHT_GREEN[0], LIGHT_GREEN[1], LIGHT_GREEN[2]));
				rendererComponent.setForeground(new Color(DARK_GREEN[0], DARK_GREEN[1], DARK_GREEN[2]));

				return rendererComponent;
			}
		});
	}

	@SuppressWarnings("serial")
	private void createTable(Object[][] data) {
		table = new JTable(data, columnNames) {

			@Override
			public Component prepareRenderer(TableCellRenderer renderer, int row, int col) {
				Component comp = super.prepareRenderer(renderer, row, col);
				int modelRow = convertRowIndexToModel(row);
				if (modelRow == displayGUI.getToHighlight() - 1) {
					comp.setBackground(new Color(GREEN[0], GREEN[1], GREEN[2]));
				} else {
					comp.setBackground(new Color(DARK_GREEN[0], DARK_GREEN[1], DARK_GREEN[2]));
				}
				return comp;
			}
		};
	}

	private void refreshReading(int taskID){
		JTextArea readText = new JTextArea();
		readTextSettings(readText);

		readText.setText(displayGUI.getDisplayCache().get(taskID-1).getDescription());
		displayGUI.setMode(MODE_READ);
		scrollPane.setViewportView(readText);
	}

	private void readTextSettings(JTextArea readText) {
		Font textFont = normalFont.deriveFont(Font.PLAIN, FONT_SIZE_READ_PAGE);
		readText.setFont(textFont);
		readText.setForeground(Color.WHITE);
		readText.setBackground(new Color(DARK_GREEN[0], DARK_GREEN[1], DARK_GREEN[2]));
		readText.setLineWrap(true);
		readText.setEditable(false);
	}
	

	private void viewHelpPage() throws IOException{
		displayGUI.setMode(MODE_HELP);
		refreshMode();
		JEditorPane helpPage = new JEditorPane();
		helpPageSettings(helpPage);
		
		HTMLEditorKit kit = new HTMLEditorKit();
		StyleSheet styleSheet = kit.getStyleSheet();
		styleSheet.addRule(FONT_STYLE_BOLD); //keys are yellow
		styleSheet.addRule(FONT_STYLE_HEADING2);
		helpPage.setEditorKit(kit);
		
		InputStream in = this.getClass().getResourceAsStream(HELP_PAGE_FILE);
        helpPage.read(in,"helpPage"); 
        
		scrollPane.setViewportView(helpPage);
	}

	private void helpPageSettings(JEditorPane helpPage) {
		Font textFont = normalFont.deriveFont(Font.PLAIN, FONT_SIZE_HELP_PAGE);
		
		helpPage.setBackground(new Color(DARK_GREEN[0], DARK_GREEN[1], DARK_GREEN[2]));
		helpPage.setEditable(false);
		helpPage.setContentType(HELP_PAGE_CONTENT_TYPE);
		helpPage.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE);
		helpPage.setFont(textFont);
		helpPage.setForeground(Color.WHITE);
	}

	public static String convertDate(DateTime currDate) {
		if (currDate != null){
			return "<html>" + String.format("%02d", currDate.getDayOfMonth())
					+ "-" + String.format("%02d", currDate.getMonthOfYear())
					+ "-" + currDate.getYear() % 100 + "<br>"
					+ String.format("%02d", currDate.getHourOfDay()) + ":"
					+ String.format("%02d", currDate.getMinuteOfHour())
					+ "</br></html>";
		}
		return null;
	}

	public static int getTaskID(int reqNum) {
		return displayGUI.getDisplayCache().get(reqNum - 1).getTaskID();
	}
	
	private void changeFeedback(String feedback) {
		feedbackLabel.setText(feedback);
	}

	private void refreshMode() {
		modeLabel.setText(displayGUI.getMode());
	}

	private void changeCommandText() {
		commandInput.setText(displayGUI.getDisplayInBox());
	}

	private DateTime formatEndDate(LFobject lf) {
		DateTime end;
		end = new DateTime(lf.getEndDate().getYear(), lf.getEndDate().getMonthOfYear(), 
				lf.getEndDate().getDayOfMonth(), lf.getEndTime().getHourOfDay(), 
				lf.getEndTime().getMinuteOfHour());
		return end;
	}

	private DateTime formatStartDate(LFobject lf) {
		DateTime start;
		start = new DateTime(lf.getStartDate().getYear(), lf.getStartDate().getMonthOfYear(), 
				lf.getStartDate().getDayOfMonth(), lf.getStartTime().getHourOfDay(), 
				lf.getStartTime().getMinuteOfHour());
		return start;
	}
	
	@Override
	public void nativeKeyPressed(NativeKeyEvent e) {
		//If key pressed = Ctrl + Space
		if (e.getKeyCode() == NativeKeyEvent.VK_SPACE
				&& e.getModifiers() == NativeKeyEvent.CTRL_MASK) {
			if (frame.getExtendedState() == JFrame.ICONIFIED) {
				frame.setExtendedState(JFrame.NORMAL);
				commandInput.requestFocusInWindow();
			} else {
				frame.setExtendedState(JFrame.ICONIFIED);
			}
		} else if (e.getKeyCode() == NativeKeyEvent.VK_M
				&& e.getModifiers() == NativeKeyEvent.CTRL_MASK) { //If key pressed = CTRL + M
			if (commandInput.isFocusOwner()) {
				scrollPane.requestFocusInWindow(); //set focus to scrollPane
			} else {
				commandInput.requestFocusInWindow(); //set focus to commandInput
			}
		} 
	}

	@Override
	public void windowOpened(WindowEvent e) {
		try {
			GlobalScreen.registerNativeHook();
		} catch (NativeHookException ex) {
            frame.setAlwaysOnTop(false);
            JOptionPane.showMessageDialog(null, MESSAGE_ERROR_NATIVE_HOOK);
            frame.setAlwaysOnTop(true);
			ex.printStackTrace();
		}

		GlobalScreen.getInstance().addNativeKeyListener(this);
	}

	@Override
	public void windowClosed(WindowEvent e) {
		GlobalScreen.unregisterNativeHook();
		System.runFinalization();
		System.exit(0);
	}

	@Override
	public void windowDeiconified(WindowEvent e) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				frame.toFront();
				frame.repaint();
				frame.setVisible(true);
				commandInput.requestFocusInWindow();
			}
		});

	}

	@Override
	public void windowDeactivated(WindowEvent e) {
		if (e.getOppositeWindow() == null){
			frame.setExtendedState(JFrame.ICONIFIED);
		}
	}
	
	private boolean isValidReadCommand(String command){
		String[] commandSplit = command.split("\\s+");
		if(commandSplit.length == 2 && isNumber(commandSplit[1])){
			return taskWithinRange(commandSplit) && Integer.parseInt(commandSplit[1]) != 0;
		}
		return false;
	}
	
	//check if the task selected is within the range of tasks
	private boolean taskWithinRange(String[] commandSplit) {
		return Integer.parseInt(commandSplit[1]) <= displayGUI.getDisplayCache().size();
	}
	
	private static boolean isNumber(String string) {
		try {
			Integer.parseInt(string);
		} catch (NumberFormatException e) {
			return false;
		}
		return true;
	}

	private boolean liveFeedExists() {
		return displayGUI.getLiveFeed() != null;
	}

	private boolean endDateTimeExists(LFobject lf) {
		return lf.getEndDate() != null && lf.getEndTime() != null;
	}

	private boolean startDateTimeExists(LFobject lf) {
		return lf.getStartDate() != null && lf.getStartTime() != null;
	}
	
	private boolean isDefaultMode() {
		return displayGUI.getMode().equals(MODE_DEFAULT);
	}
	
	private boolean commandTyped() {
		return !commandInput.getText().trim().isEmpty();
	}

	private boolean isHelpMode() {
		return displayGUI.getMode().equals(MODE_HELP);
	}

	private boolean isReadMode() {
		return displayGUI.getMode().equals(MODE_READ);
	}
	
	private boolean isEditMode() {
		return displayGUI.getMode() == MODE_EDIT;
	}
	
	public static GUIobject getDisplayObject(){
		return displayGUI;
	}

	@Override
	public void windowClosing(WindowEvent e) {
		//Unimplemented method
	}

	@Override
	public void windowIconified(WindowEvent e) {
		//Unimplemented method
	}

	@Override
	public void windowActivated(WindowEvent e) {
		//Unimplemented method
	}

	@Override
	public void insertUpdate(DocumentEvent e) {
		//Unimplemented method
	}

	@Override
	public void removeUpdate(DocumentEvent e) {
		//Unimplemented method
	}

	@Override
	public void changedUpdate(DocumentEvent e) {
		//Unimplemented method
	}

	@Override
	public void nativeKeyTyped(NativeKeyEvent arg0) {
		//Unimplemented method
	}

	@Override
	public void nativeKeyReleased(NativeKeyEvent e) {
		//Unimplemented method
	}

	public void tableChanged(TableModelEvent e) {
		//Unimplemented method
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		//Unimplemented method
	}
}

